package updown.service.updown;

import com.netflix.appinfo.InstanceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import updown.dao.EurekaServiceDao;
import updown.data.SseCacheData;
import updown.domain.*;
import updown.service.jar.LocalFileService;
import updown.service.task.ScheduleTaskService;
import updown.service.task.ServerHostService;
import updown.service.task.TaskInfoService;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>Title: ww.kaixin.downupservice.service </p>
 * <p>Description:to-22-6-1: - 查询本地数据库维护的 服务列表 </p>
 *
 * @Author:jiangkaixin
 * @Date:2021/12/20
 * @Version: 1.0
 */
@Slf4j
@Service
public class LocalService {
    @Autowired
    private EurekaServiceDao eurekaServiceDao;

    @Autowired
    private LocalFileService localFileService;

    @Autowired
    private ServerHostService hostService;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private SseCacheData sseCacheData;

    @Autowired
    private EurekaService eurekaService;

    @Autowired
    private ScheduleTaskService scheduleTaskService;

    @Autowired
    private TaskInfoService taskInfoService;

    /**
     * 添加
     *
     * @param serviceInfo
     * @return
     */
    public String add(ServiceInfo serviceInfo) {
        if (StringUtils.isEmpty(serviceInfo.getServiceName()) || StringUtils.isEmpty(serviceInfo.getServerList())){
            return "服务名和服务器列表不能为空";
        }
        try {
            String[] split = serviceInfo.getServerList().split(",");
            List<String> stringList = Arrays.asList(split);
            List<String> hosts = stringList.stream().filter(item -> !StringUtils.isEmpty(item)).collect(Collectors.toList());
            for (String host : hosts) {
                if (hostService.getServerHostName(host) == null){
                    return host + "还未配置，请线配置服务器";
                }
            }
        } catch (Exception e) {
            log.info("getServerList().split error :{}",e);
            return "服务列表不符合格式";
        }
        ServiceInfo byName = eurekaServiceDao.getByName(serviceInfo.getServiceName());
        if (byName != null) {
            return "此服务已存在";
        }
        eurekaServiceDao.add(serviceInfo);
        return "添加成功";
    }

    /**
     * 添加服务器
     * @param serverHost
     * @return
     */
    public String addHost(ServerHost serverHost) {
        if (StringUtils.isEmpty(serverHost.getName()) ||
                StringUtils.isEmpty(serverHost.getHost()) ||
                serverHost.getPort() == 0||
                StringUtils.isEmpty(serverHost.getUser()) ||
                StringUtils.isEmpty(serverHost.getPassword())){
            return "字段都必填";
        }
        hostService.add(serverHost);
        return "添加成功";
    }

    /**
     * 本地数据库维护的 根据名字查到 服务信息
     *
     * @param serviceName
     * @return
     */
    public ServiceInfo getByName(String serviceName) {
        return eurekaServiceDao.getByName(serviceName);
    }

    /**
     * 查询所有
     *
     * @return
     */
    public List<ServiceMapDto> getAll() {
        List<ServiceInfo> all = eurekaServiceDao.getAll();
        List<ServiceMapDto> dtos = all.stream().map(item -> {
            TaskWrapperMapperBean taskWrapper = taskInfoService.getLatestDownUpRecord(item.getServiceName());
            if (taskWrapper != null){
                item.setLastRestartTime(taskWrapper.getEndTime());
                item.setCurrentVersion(taskWrapper.getJarInfo());
            }
            return new ServiceMapDto(item);
        }).collect(Collectors.toList());
        // 最近的替换版本和时间

        // 查询是否有 定时任务
        List<DownUpSchedule> schedules = scheduleTaskService.getSchedulingTasks();
        log.info("查询是否有 定时任务:{}",schedules);
        if (!schedules.isEmpty()){
            dtos.forEach(dto->{
                for (DownUpSchedule schedule : schedules) {
                    if(dto.getServiceName().equals(schedule.getServiceName())){
                        DownUpScheduleWrapper downUpScheduleWrapper = new DownUpScheduleWrapper();
                        dto.getSchedules().add(downUpScheduleWrapper.convert(schedule));
                    }
                }
            });
        }
        log.info("查询 服务列表信息:{}", dtos);
        return dtos;
    }

    /**
     * 查询 对应的服务，downup 服务本地服务器缓存的 jar包信息
     *
     * @param serviceName
     */
    public List<String> getJarInfo(String serviceName) {
        log.info("getJarInfo(),serviceName:{}",serviceName);
        List<String> localJarFileByServiceName = localFileService.getLocalJarFileByServiceName(serviceName);
        return localJarFileByServiceName;
    }

    /**
     * 检查 本地 和 eureka server 中 服务的注册信息是否一致。主要是比较 instanceId 的个数 和 全部匹配一致
     * @param taskWrapper
     */
    public void doCheckLocalAndEurekaSame(TaskWrapper taskWrapper) {
        log.info("检查 eureka 中对应的 服务信息，和本地是否一致");
        List<ServiceInstance> localServerInstances = doCheckServiceExistInLocal(taskWrapper);
        List<InstanceInfo> eurekaInstances = doCheckServiceExistInEureka(taskWrapper);
        if (localServerInstances.size() != eurekaInstances.size()) {
            log.info("检查 eureka 中对应的 服务信息，不一致，数量都不一致");
            sseCacheData.sendLastMsgAndThrowEx("downUp 和 eureka 中服务实例的【个数】在服务替换前检查不一致，替换停止", taskWrapper);
        }
        List<String> local = localServerInstances.stream().map(instance -> instance.getInstanceId()).collect(Collectors.toList());
        List<String> eureka = eurekaInstances.stream().map(instanceInfo -> instanceInfo.getInstanceId()).collect(Collectors.toList());
        log.info("本地 instanceId列表:{}，server 的instanceId列表:{}", local, eureka);
        boolean same = local.containsAll(eureka);
        if (!same) {
            sseCacheData.sendLastMsgAndThrowEx("downUp 和 eureka 中服务实例【instance 不一致】在服务替换前检查不一致，替换停止", taskWrapper);
        }
    }

    /**
     * 本地 有无 serviceName 对应的 实例信息  有无服务
     * @param taskWrapper
     * @return
     */
    private List<ServiceInstance> doCheckServiceExistInLocal(TaskWrapper taskWrapper) {
        String serviceName = taskWrapper.getServiceInfo().getServiceName();
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        //http://localhost:8761/eureka/apps/FEIGN-PROVIDER/DESKTOP-HGTNR01:feign-provider:8001/status?value=DOWN
        if (instances == null || instances.isEmpty()) {
            log.info("在downUp服务本地，无当前的服务>>>:{}");
            sseCacheData.sendLastMsgAndThrowEx("在downUp服务本地未发现【" + serviceName + "】服务", taskWrapper);
        }
        log.info("本地的服务列表:{}", instances);
        return instances;
    }

    /**
     * 注册中心有无服务
     * @param taskWrapper
     * @return
     */
    private List<InstanceInfo> doCheckServiceExistInEureka(TaskWrapper taskWrapper) {
        String serviceName = taskWrapper.getServiceInfo().getServiceName();
        List<InstanceInfo> instanceInfos = eurekaService.getInstancesByNameFromEureka(serviceName);
        //http://localhost:8761/eureka/apps/FEIGN-PROVIDER/DESKTOP-HGTNR01:feign-provider:8001/status?value=DOWN
        if (instanceInfos == null || instanceInfos.isEmpty()) {
            log.info("在注册中心中，无当前的服务>>>:{}");
            sseCacheData.sendLastMsgAndThrowEx("在注册中心中，无当前的服务", taskWrapper);
        }
        log.info("注册中心中的服务列表:{}", instanceInfos);
        return instanceInfos;
    }

    /**
     * 获取服务在本地的 instance 信息
     * @param taskWrapper
     * @return
     */
    public List<ServiceInstance> getLocalInstancesInfo(TaskWrapper taskWrapper) {
        String serviceName = taskWrapper.getServiceInfo().getServiceName();
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        return instances;
    }
}
